import ThreadPool as TP
import VariablePool as VP
from Event import *
from Common import *
import threading

INPUT_VARIABLE = 1
OUTPUT_VARIABLE = 2
MEM_VARIABLE = 4

class Variable(object):
    
    def __init__(self, ioflag, name, alias = '', initval = None, ioobj = None):
        if VP.varpool.HasVariable(name):
            raise VariableNameException("Variable pool has a same name '%s' variable." % (name))
        self.name = None
        self.alias = None
        self.value = None
        self.ioflag = ioflag
        self.ioobject = ioobj
        self.eventtable = {}
        self.lock = threading.Lock()
        
        self.name = name
        self.alias = alias
        self.value = initval
        
        VP.varpool.AddVariable(self)
        
    def SetIoObject(self, ioobj):
        self.ioobject = ioobj
        
    def GetIoObject(self):
        return self.ioobject
    
    def GetIoFlag(self):
        return self.ioflag
        
    def HasName(self):
        return self.name != None
        
    def GetName(self):
        return self.name
    
    def SetName(self, name):
        self.name = name
        
    Name = property(GetName, SetName, doc = 'Variable Name')
    
    def GetAlias(self):
        return self.alias
    
    def SetAlias(self, alias):
        self.alias = alias
        
    Alias = property(GetAlias, SetAlias, doc = 'Variable Alias')
    
    def GetValue(self):
        with self.lock:
            return self.value
    
    def SetValue(self, value):
        with self.lock:
            if self.ioflag & INPUT_VARIABLE:
                self.InputValue(value)
            if self.ioflag & OUTPUT_VARIABLE:
                self.OutputValue(value)
        
    Value = property(GetValue, SetValue, doc = 'Variable Value')
    
    def CheckValue(self, value):
        raise NotImplementedError("Method Variable::CheckValue not implemented.")
    
    def InputValue(self, value):
        raise NotImplementedError("Method Variable::InputValue not implemented.")
    
    def OutputValue(self, value):
        raise NotImplementedError("Method Variable::OutputValue not implemented.")
    
    def Bind(self, evttype, callobj):
        if not callable(callobj):
            return
        if not self.eventtable.has_key(evttype):
            self.eventtable[evttype] = []
        self.eventtable[evttype].append(callobj)
        
    
class Digital(Variable):
    
    def __init__(self, ioflag, name, alias = '', initval = False, ioobj = None):
        Variable.__init__(self, ioflag, name, alias, initval, ioobj)
        
    def GetValue(self):
        with self.lock:
            if self.value:
                return 1
            return 0
        
    def InputValue(self, value):
        if self.value and not value:
            #print "%s=%s" % (self.name, repr(value))
            self.value = value
            self._DoPegativeEdge(value)
        elif not self.value and value:
            #print "%s=%s" % (self.name, repr(value))
            self.value = value
            self._DoPositiveEdge(value)
            
    def OutputValue(self, value):
        if self.ioobject:
            #print "%s=%s" % (self.name, repr(value))
            self.ioobject.Output(value and 1 or 0)
        self.value = value
        
    def CheckValue(self, value):
        return True
            
    def _DoPositiveEdge(self, value):
        if not self.eventtable.has_key(EVT_POSITIVE_EDGE):
            return
        callobjs = self.eventtable[EVT_POSITIVE_EDGE]
        for callobj in callobjs:
            TP.threadpool.AddTask(callobj, PositiveEdge(self))
    
    def _DoPegativeEdge(self, value):
        if not self.eventtable.has_key(EVT_PEGATIVE_EDGE):
            return
        callobjs = self.eventtable[EVT_PEGATIVE_EDGE]
        for callobj in callobjs:
            TP.threadpool.AddTask(callobj, PegativeEdge(self))

class Analog(Variable):
    def __init__(self, ioflag, name, alias = '', initval = 0.0, ioobj = None):
        Variable.__init__(self, ioflag, name, alias, initval, ioobj)
        
    def InputValue(self, value):
        if self.CheckValue(value):
            self.value = value
            
    def OutputValue(self, value):
        if self.ioobject:
            print "%s=%s" % (self.name, repr(value))
            TP.threadpool.AddTask(self.ioobject.Output, value)
        self.value = value
        
    def CheckValue(self, value):
        return type(value) == type(0.0)
        
class Array(Variable):
    def __init__(self, ioflag, name, alias = '', initval = [], ioobj = None):
        Variable.__init__(self, ioflag, name, alias, initval, ioobj)
        
    def InputValue(self, value):
        #print "%s=%s" % (self.name, repr(value))
        self.value.append(value)
        
    def CheckValue(self, value):
        True
        
    def Clear(self):
        self.value = []
        
    def GetCount(self):
        return len(self.value)
    
    def __getitem__(self, index):
        return self.value[index]
    
    def __setitem__(self, index, value):
        self.value[index] = value
        
    def __iter__(self):
        return self.value.__iter__()
    
class Integer(Variable):
    def __init__(self, ioflag, name, alias = '', initval = 0, ioobj = None):
        Variable.__init__(self, ioflag, name, alias, initval, ioobj)
        
    def InputValue(self, value):
        if self.CheckValue(value):
            self.value = value
            
    def OutputValue(self, value):
        if self.ioobject:
            print "%s=%s" % (self.name, repr(value))
            TP.threadpool.AddTask(self.ioobject.Output, value)
        self.value = value
        
    def CheckValue(self, value):
        return type(value) == type(0)
        